package tech.eyao.hs60x.awareUtil;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;

import com.alibaba.fastjson.JSON;
import com.aliyuncs.DefaultAcsClient;
import com.aliyuncs.IAcsClient;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsRequest;
import com.aliyuncs.dysmsapi.model.v20170525.SendSmsResponse;
import com.aliyuncs.http.MethodType;
import com.aliyuncs.profile.DefaultProfile;
import com.aliyuncs.profile.IClientProfile;

import tech.eyao.hs60x.common.CommonConstants;
import tech.eyao.hs60x.common.ConstantsKey;
import tech.eyao.hs60x.common.ReturnCode;
import tech.eyao.hs60x.dto.AccountDTO;
import tech.eyao.hs60x.dto.BaseResult;
import tech.eyao.hs60x.enums.AccountType;
import tech.eyao.hs60x.enums.SmsTemplateCodeEnums;
import tech.eyao.hs60x.model.domain.AccountDO;
import tech.eyao.hs60x.model.domain.AccountRelationDO;
import tech.eyao.hs60x.redis.template.IntegerRedisTemplate;
import tech.eyao.hs60x.service.AccountRelationService;
import tech.eyao.hs60x.service.AccountService;
import tech.eyao.hs60x.utils.HttpClientUtil;
import tech.eyao.hs60x.utils.TokenUtils;

/**
 * 类CommonServiceUtil.java的实现描述：通用单例服务
 */
@Component
public class CommonServiceUtil implements ApplicationContextAware {
    private static final Logger       logger = LoggerFactory.getLogger(CommonServiceUtil.class);
    private static ApplicationContext applicationContextInit;
    @Autowired
    private IntegerRedisTemplate      redisTemplate;

    @Autowired
    private AccountRelationService    accountRelationService;
    @Autowired
    private AccountService            accountServiceImpl;
    
    public static CommonServiceUtil getInstance() {
        return getApplicationContextInit().getBean(CommonServiceUtil.class);
    }

    /**
     * 重写方法
     */
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        setApplicationContextInit(applicationContext);
    }

    public static ApplicationContext getApplicationContextInit() {
        return applicationContextInit;
    }

    public static void setApplicationContextInit(ApplicationContext applicationContextInit) {
        CommonServiceUtil.applicationContextInit = applicationContextInit;
    }

    /**
     * @description 短信下发
     * @param phoneNo
     * @param smsBusType
     * @return
     */
    public BaseResult sendCommonSms(String phoneNo, String smsBusType) {
        Map<String, Object> hsCodeParam = new HashMap<String, Object>();
        int smsCount = 0;
        try {
            // 校验手机下发次数
            Object rdSmsCount = redisTemplate.opsForValue().get(CommonConstants.SMS_COUNT + phoneNo);
            if (null != rdSmsCount && (int) rdSmsCount >= 1) {
                return BaseResult.isBussinessFail("短信下发频繁，请一分钟后尝试!");
            }

            // 可自助调整超时时间
            System.setProperty("sun.net.client.defaultConnectTimeout", "10000");
            System.setProperty("sun.net.client.defaultReadTimeout", "10000");
            // 初始化acsClient
            IClientProfile profile = DefaultProfile.getProfile(CommonConstants.ALI_SMS_ENDPOINT_NAME,
                    CommonConstants.ALI_SMS_ACCESSKEY_ID, CommonConstants.ALI_SMS_ACCESSKEY_SECRET);
            DefaultProfile.addEndpoint(CommonConstants.ALI_SMS_ENDPOINT_NAME, CommonConstants.ALI_SMS_ENDPOINT_NAME,
                    CommonConstants.ALI_SMS_PRODUCT, CommonConstants.ALI_SMS_SREVER_DOMAIN);
            IAcsClient acsClient = new DefaultAcsClient(profile);
            SendSmsRequest request = new SendSmsRequest();
            // POST
            request.setMethod(MethodType.POST);
            request.setPhoneNumbers(phoneNo);
            // 短信签名
            request.setSignName(CommonConstants.ALI_SMS_SIGNNAME);
            request.setTemplateCode(SmsTemplateCodeEnums.getValueByTemplateType(smsBusType).getTemplateCode());
            // OTP注册通用模板
            if (SmsTemplateCodeEnums.LOGIN.getTemplateType().equals(smsBusType)) {
                hsCodeParam.put("code", (int) ((Math.random() * 9 + 1) * 1000));
                request.setTemplateParam(JSON.toJSONString(hsCodeParam));
            }
            SendSmsResponse sendSmsResponse = acsClient.getAcsResponse(request);
            if (sendSmsResponse.getCode() == null || !sendSmsResponse.getCode().equals("OK")) {
                logger.warn("sendSmsResponse:{}", ToStringBuilder.reflectionToString(sendSmsResponse));
                return BaseResult.isBussinessFail("短信下发失败!");
            }
            // 计入缓存
            putTairCache(phoneNo, hsCodeParam, smsCount, null);

            return BaseResult.isSuccess();
        } catch (Exception e) {
            logger.error(e.getMessage());
        }
        return BaseResult.isDeFaultNoData();

    }

    /**
     * 获取城市数据
     * 
     * @param city
     * @return
     */
    public BaseResult getWeather(String city) {
        BaseResult baseResult = new BaseResult();
        try {
            Map<String, String> paramMap = new HashMap<String, String>();
            paramMap.put("city", city);
            String response = HttpClientUtil.get(CommonConstants.WEATHER_DOMAIN, paramMap, null);
            if (StringUtils.isBlank(response)) {
                return BaseResult.isFailure("get weather is fail!");
            }
            baseResult.message = ReturnCode.SUCCESS_CODE.getDesc();
            baseResult.code = ReturnCode.C_SUCCESS_CODE;
            baseResult.data = JSON.parseObject(response);
        } catch (Exception e) {
            logger.error("CommonService getWeather error." + e.getMessage());
            return BaseResult.isDeFaultFailure();

        }
        return BaseResult.isDeFaultNoData();
    }

    /**
     * 存储redis
     * 
     * @param phoneNo
     * @param hsCodeParam
     * @param ipAdress
     * @param smsCount
     */
    private void putTairCache(String phoneNo, Map<String, Object> hsCodeParam, int smsCount, String ipAdress) {
        // 注册短信时效性
        redisTemplate.opsForValue().set(ConstantsKey.getRdSendSmsCachePhone(phoneNo), (int) hsCodeParam.get("code"),
                CommonConstants.VISIT_LIMIT_MINUTE_5,TimeUnit.SECONDS);
        // 手机一分钟下发次数控制
        redisTemplate.opsForValue().set(CommonConstants.SMS_COUNT + phoneNo, 1, CommonConstants.SEND_SMS_TIME,
                TimeUnit.SECONDS);

    }

    /**
     * 校验用户是否满足某个权限校色（管理员）
     * 
     * @return
     */
    public boolean checkUserCommonRole() {
        BaseResult rs = accountServiceImpl.getAccountDetail(TokenUtils.getUserId());
        if (null == rs || null == rs.getData()) {
            return false;
        }
        AccountDTO accountDTO = (AccountDTO) rs.getData();
        if (AccountType.PHONE.getValue() == accountDTO.accountType) {
            return accountRelationService.checkUserIsAdmin(accountDTO.accountId);
        }
        return false;
    }
    /**
     * 校验当前终端设备是否被初次绑定
     * @param deviceImei
     * @return
     */
    public boolean checkDeviceIsBind(AccountDO accountDO) {
        //合法性校验
        if (null == accountDO || StringUtils.isBlank(accountDO.getDeviceId())) {
            return false;
        }
        accountDO = accountServiceImpl.queryAccoutByDeviceParams(accountDO);
        if (null == accountDO) {
           return false;
        }
        //获取当前设备的信息获取relation绑定关系
        AccountRelationDO accountRelationDO =accountRelationService.getAccountAdminByWatchId(accountDO.getId());
        if(null == accountRelationDO) {
            return false;
        }
        return true;
    }
    
    /**
     * 是否绑定
     * @param userId
     * @param watchId
     * @return
     */
    public boolean isBindWatch(long userId, String deviceId, String phone) {
    	AccountDO accountDO = new AccountDO();
    	accountDO.setDeviceId(deviceId);
    	accountDO.setPhone(phone);
    	accountDO = accountServiceImpl.queryAccoutByDeviceParams(accountDO);
    	if(null == accountDO) {
    		return Boolean.FALSE;
    	}
    	return accountRelationService.isBindWatch(userId, accountDO.getId());
    }
}
